﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TUtils.BasicHelper;

namespace MMessaging.Address
{
	/// <summary>
	/// Adresse
	/// Es gibt zwei verschiedene Typen von Adressen:
	/// 1. Serviceadressen: Jede Serviceinstanz, die das Adressprotokoll implemntiert
	/// hat eine konkrete und eindeutige Serviceadresse.
	/// 2. Rollenadressen: Eine Rolle identifiziert eine Gruppe von Empfängern.
	///    Man beachte, dass man keine Rollenadresse vergeben sollte, die bereits
	///    als Serviceadresse verwendet werden. Der Sinn einer Rollenadresse ist, dass 
	///    man eine Message an eine Service-Rolle schicken kann, und nicht die konkrete 
	///    Adresse des Service zu kennen braucht. Außerdem können auf diese Weise 
	///    mehrere Services sich für bestimmte Messages registrieren, in dem sie 
	///    ihre Rollen bekanntgeben.
	/// </summary>
	public class MAddress : EqualityImplementor<MAddress>
	{
	
		#region private

		private byte[] _addressData;

		#endregion

		#region constructor

		/// <summary>
		/// 
		/// </summary>
		/// <param name="address">
		/// Adresse oder Rolle
		/// </param>
		public MAddress(string address)
		{
			try
			{
				_addressData = address.Select(character => Convert.ToByte(character)).ToArray();
			}
			catch (OverflowException e)
			{
				throw new ApplicationException("address couldn't be converted to a byte[] " + address, e);
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="addressData">
		/// Adresse oder Rolle
		/// </param>
		public MAddress(byte[] addressData)
		{
			_addressData = addressData;
		}

		#endregion

		#region public

		/// <summary>
		/// Rohdaten der Adresse oder Rolle
		/// </summary>
		public byte[] AddressData 
		{ 
			get
			{
				return _addressData;
			}
		}

		/// <summary>
		/// Adressdaten als ASCII string. Die Rohdaten werden als ASCII String
		/// interpretiert
		/// </summary>
		public string AddressDataAsASCII
		{
			get
			{
				return _addressData.ToStringASCII();
			}
		}

		/// <summary>
		/// Adressdaten als HEX string. Die Rohdaten werden als HEX String
		/// dargestellt
		/// </summary>
		public string AddressDataAsHexString
		{
			get
			{
				return _addressData.ToHex();
			}
		}

		/// <summary>
		/// "bytes=0x{0}, ascii={1}"
		/// </summary>
		/// <returns></returns>
		public override string ToString()
		{
			return string.Format(
				"bytes=0x{0}, ascii={1}",
				_addressData.ToHex(),
				AddressDataAsASCII
				);
		}

		#endregion

		#region equality implementation
		/// <summary>
		/// don't call this method directly. Use "==" or Equals(..) instead.
		/// </summary>
		public override bool IsEqualInternal(MAddress obj1, MAddress obj2)
		{
			return obj1._addressData.AreEquals(obj2._addressData);
		}

		public override int GetHashCodeInternal(MAddress obj)
		{
			int hashCode = 0;
			int len = _addressData.Length;
			for (int i = 0; i < len; i++)
				hashCode ^= (_addressData[i] << (i % 4));
			return hashCode;
		}

		public static bool operator ==(MAddress x, MAddress y)
		{
			return EqualsStatic(x, y);
		}

		public static bool operator !=(MAddress x, MAddress y)
		{
			return !(x == y);
		}
		#endregion
	}
}
